#include "cell.h"

Cell::Cell()
{
    nTransistors = new QList<Transistor*>();
    pTransistors = new QList<Transistor*>();
    metalItems = new QList<Metal*>();
    m1Items = new QList<Metal*>();
    m2Items = new QList<Metal*>();
    m1PinItems = new QList<Metal*>();
    poItems = new QList<Metal*>();
    coItems = new QList<Metal*>();
    diffItems = new QList<Metal*>();
    vias = new QList<Via*>();
    vccRectItem = new Metal();
    vccRectItem->net = "vcc";

    gndRectItem = new Metal();
    gndRectItem->net = "gnd";

    nWellRectItem = new Metal();
    nPlusRectItem = new Metal();
    pPlusRectItem = new Metal();

    vccStrapItem = new Strap();
    gndStrapItem = new Strap();

    m1Items->append(vccRectItem);
    m1Items->append(gndRectItem);

    metalItems->append(nWellRectItem);
    metalItems->append(nPlusRectItem);
    metalItems->append(pPlusRectItem);

    this->gndHeight = ((Rules::getRule("CO.E.1")*2) + Rules::getRule("CO.W.1") + (Rules::getRule("NP.E.1")*2));
    this->vccHeight = ((Rules::getRule("CO.E.1")*2) + Rules::getRule("CO.W.1") + (Rules::getRule("PP.E.1")*2));
    this->pmosHeight = ((Rules::getRule("CO.E.1")*2) + Rules::getRule("CO.W.1"))*16;
    this->nmosHeight = ((Rules::getRule("CO.E.1")*2) + Rules::getRule("CO.W.1"))*10;

    alreadyPlaced = false;
}

QString Cell::getCellName() const
{
    return cellName;
}

void Cell::addTransistor(Transistor *t)
{
    if(t->transistorType.compare("NMOS",Qt::CaseInsensitive)==0)
        nTransistors->append(t);
    else
        pTransistors->append(t);
}

void Cell::setCellName(QString name)
{
    cellName = name;
}

void Cell::addPin(QString pin)
{
    pins.append(pin);
}

void Cell::setTransistorYPosition(Transistor *t)
{
    if(t->transistorType.compare("PMOS",Qt::CaseInsensitive) == 0)
    {
        t->setY(pPlusRectItem->y() - Rules::getRule("PO.O.1") + Rules::getRule("PP.E.1"));

        float diff = vccStrapItem->y() + vccStrapItem->boundingRect().height() - Rules::getRule("NP.E.1");

        if(t->y() - diff < Rules::getRule("PO.C.1"))
            t->setY(diff + Rules::getRule("PO.C.1"));
    }
    else
    {
        t->setY(nPlusRectItem->y() + nmosHeight - t->gateRect.height() +  Rules::getRule("PO.O.1") - Rules::getRule("NP.E.1"));

        float diff = gndStrapItem->y() + Rules::getRule("PP.E.1");

        if(diff - (t->y() + t->gateRect.height()) <  Rules::getRule("PO.C.1"))
            t->setY(gndStrapItem->y() - t->gateRect.height() + Rules::getRule("PP.E.1") - Rules::getRule("PO.C.1"));
    }
}

void Cell::setTransistorYPosition()
{
    foreach(Transistor *t, *(pTransistors))
        setTransistorYPosition(t);

    foreach(Transistor *t, *(nTransistors))
        setTransistorYPosition(t);
}

void Cell::setTransistorsScenePosition()
{
    setInitialScenePositions();
    fixVerticalAlignment();

    setMaxX();
}

void Cell::setInitialScenePositions()
{
    this->setInitialScenePositions(pTransistors);
    this->setInitialScenePositions(nTransistors);
}

Transistor* Cell::getTransistorByPosIndex(QList<Transistor *> *transistors, Transistor *curT)
{
    foreach(Transistor *t , *(transistors))
        if(t->getPosIndex() == curT->getPosIndex())
            return t;

    return 0;
}

Transistor* Cell::getTransistorByPosIndex(QList<Transistor *> *transistors, int posIndex)
{
    foreach(Transistor *t , *(transistors))
        if(t->getPosIndex() == posIndex)
            return t;

    return 0;
}

void Cell::fixVerticalAlignment(QList<Transistor *> *collT1, QList<Transistor *> *collT2)
{
    foreach(Transistor *t1, *(collT1))
    {
        Transistor *t2 = getTransistorByPosIndex(collT2, t1);

        if(!t2)
            continue;

        if(t1->x() < t2->x())
            translateTransistors(collT1, t1->posIndex, t2->x() - t1->x());
        else if(t2->x() < t1->x())
            translateTransistors(collT2, t1->posIndex, t1->x() - t2->x());
    }
}

void Cell::fixVerticalAlignment()
{
    fixVerticalAlignment(nTransistors, pTransistors);
    fixVerticalAlignment(pTransistors, nTransistors);
}

void Cell::translateTransistors(QList<Transistor *> *transistors, int startIndex, float dx)
{
    foreach(Transistor *t, *transistors )
        if(t->posIndex >= startIndex)
            t->setX(t->x() + dx);
}

boolean Cell::hasGap(Transistor* t,  QList<Transistor*> *transistors )
{
    int i = transistors->indexOf(t);

    return (i>0) && ((t->getPosIndex() - transistors->at(i-1)->getPosIndex()) != 1);
}

int Cell::countContacts(Transistor* tr, QList<Transistor*> *transistors)
{
    int count = 0;
    QString net = getLeftNet(tr);

    foreach(Transistor *t, *(transistors))
    {
        if((tr != t) && (t->sourceNetName.compare(net) == 0 ||
           t->drainNetName.compare(net)  == 0 ||
           t->gateNetName.compare(net)   == 0))
            count++;
    }

    return count;
}

boolean Cell::hasContact(Transistor* t)
{
    if(getLeftNet(t).compare("vcc") == 0 || getLeftNet(t).compare("gnd") == 0)
        return true;

    return (countContacts(t, pTransistors) + countContacts(t, nTransistors)) > 1;
}

QString Cell::getLeftNet(Transistor* t)
{
    if(t->flipped)
        return t->drainNetName;

    return t->sourceNetName;
}

void Cell::setInitialScenePositions(QList<Transistor *> *t)
{
    qreal contactSpace = Rules::getRule("CO.W.1") + Rules::getRule("CO.C.1") + Rules::getRule("CO.E.1") + Rules::getRule("PO.W.1a");
    qreal initialTranslate =  Rules::getRule("PP.E.1") + Rules::getRule("CO.W.1") + Rules::getRule("CO.C.1") + Rules::getRule("CO.E.1") + Rules::getRule("PO.W.1a")/2;
    qreal gapSpace = ((Rules::getRule("CO.W.1") + Rules::getRule("CO.C.1") + Rules::getRule("CO.E.1"))*2) + Rules::getRule("PO.W.1a") + Rules::getRule("OD.S.1");
    qreal poContactWidth = Rules::getRule("CO.E.2")*2 + Rules::getRule("CO.W.1");
    qreal noContactSpace = Rules::getRule("PO.S.1") + Rules::getRule("PO.W.1a");// + Rules::getRule("PO.W.1a") + (poContactWidth - Rules::getRule("PO.W.1a"))/2;


    for(int i=0; i<t->size(); i++)
    {
        if(t->at(i)->routedPos.x() != 0)
            t->at(i)->setPos(t->at(i)->routedPos);
        else
        {
            if(i==0)
            {
                t->at(i)->setX(initialTranslate);
                continue;
            }

            if(hasGap(t->at(i), t))
                t->at(i)->setX(t->at(i-1)->x() + gapSpace);
            else if(hasContact(t->at(i)))
            {
                if(t->at(i-1)->w == t->at(i)->w)
                    t->at(i)->setX(t->at(i-1)->x() + contactSpace);
                else
                    t->at(i)->setX(t->at(i-1)->x() + contactSpace + Rules::getRule("PO.C.1"));
            }
            else
            {
                if(t->at(i-1)->w == t->at(i)->w)
                    t->at(i)->setX(t->at(i-1)->x() + noContactSpace);
                else
                {
                    t->at(i-1)->removeRightContact();
                    t->at(i)->removeLeftContact();

                    t->at(i)->setX(t->at(i-1)->x() + noContactSpace + Rules::getRule("PO.C.1"));
                }
            }
        }
    }
}


void Cell::setMaxX()
{
    qreal maxXp = pTransistors->last()->scenePos().x() + pTransistors->last()->boundingRect().right();
    qreal maxXn = nTransistors->last()->scenePos().x() + nTransistors->last()->boundingRect().right();

    maxX = maxXn > maxXp ? maxXn : maxXp;
}

void Cell::setVccGndPosition()
{
    vccRectItem->clear();
    vccRectItem->bottomRight = QPointF(maxX + (Rules::getRule("PP.E.1")), vccHeight);
    vccRectItem->setPos(0,0);

    gndRectItem->clear();
    gndRectItem->bottomRight = QPointF(maxX + (Rules::getRule("PP.E.1")), gndHeight);
    gndRectItem->setPos(0, gndStrapItem->y() - (gndHeight - gndStrapItem->strapWidth) - Rules::getRule("NP.E.1") );
}

void Cell::setPPlusPosition()
{
    this->pPlusRectItem->clear();
    this->pPlusRectItem->bottomRight = QPointF(maxX + Rules::getRule("PP.E.1"),this->pmosHeight);
    this->pPlusRectItem->setMetalType("PPLUS");
    this->pPlusRectItem->setPos(0, (Rules::getRule("CO.E.1"))*2 + Rules::getRule("CO.W.1") + Rules::getRule("NP.E.1"));
}

void Cell::setNPlusPosition()
{
    this->nPlusRectItem->clear();
    this->nPlusRectItem->bottomRight = QPointF(maxX + Rules::getRule("NP.E.1") , this->nmosHeight);
    this->nPlusRectItem->setMetalType("NPLUS");
    this->nPlusRectItem->setPos(0,pPlusRectItem->y() + pPlusRectItem->boundingRect().height());
}

void Cell::setNWellPosition()
{
    this->nWellRectItem->clear();
    this->nWellRectItem->bottomRight = QPointF(maxX + (Rules::getRule("OD.C.4")*2) - Rules::getRule("NP.E.1"),
                                               this->pmosHeight + ((Rules::getRule("CO.E.1")*2) + Rules::getRule("CO.W.1") + Rules::getRule("NP.E.1") + Rules::getRule("OD.C.4")) );
    this->nWellRectItem->setMetalType("NWELL");
    this->nWellRectItem->setPos(-(Rules::getRule("OD.C.4")  - Rules::getRule("PP.E.1")),-Rules::getRule("OD.C.4"));
}

Metal* Cell::getGndStrapBlockingPoly()
{
    Metal *leftPo = 0;

    foreach(Metal* po, *(poItems))
        if(po->y() > nTransistors->first()->y() + nTransistors->first()->gateRect.height())
            if(!leftPo || po->x() < leftPo->x())
                leftPo = po;
    return leftPo;
}

Metal* Cell::getVccStrapBlockingPoly()
{
    Metal *leftPo = 0;

    foreach(Metal* po, *(poItems))
        if(po->y() < pTransistors->first()->y())
            if(!leftPo || po->x() < leftPo->x())
                leftPo = po;
    return leftPo;
}

void Cell::setVccGndStraps()
{

    Metal* vccStrapBlockingPoly = getVccStrapBlockingPoly();
    Metal* gndStrapBlockingPoly = getGndStrapBlockingPoly();

    if(vccStrapBlockingPoly)
        this->vccStrapItem->strapHeight = vccStrapBlockingPoly->x() -  Rules::getRule("PO.C.1") + Rules::getRule("PP.E.1") ;
    else
        this->vccStrapItem->strapHeight = maxX + (Rules::getRule("PP.E.1"));

    this->vccStrapItem->strapWidth = ((Rules::getRule("NP.E.1") + Rules::getRule("CO.E.1"))*2) + Rules::getRule("CO.W.1");
    this->vccStrapItem->strapType = "NTAP";
    this->vccStrapItem->setPos(0, -Rules::getRule("NP.E.1"));

    if(gndStrapBlockingPoly)
        this->gndStrapItem->strapHeight = gndStrapBlockingPoly->x() -  Rules::getRule("PO.C.1") + Rules::getRule("PP.E.1") ;
    else
        this->gndStrapItem->strapHeight = maxX + (Rules::getRule("PP.E.1"));

    this->gndStrapItem->strapWidth = ((Rules::getRule("PP.E.1") + Rules::getRule("CO.E.1"))*2) + Rules::getRule("CO.W.1");
    this->gndStrapItem->strapType = "PTAP";
    this->gndStrapItem->setPos(0, nPlusRectItem->y() + nmosHeight);
}


bool lessThanGateNetName(Transistor *t1, Transistor *t2)
{
    return t1->gateNetName.compare(t2->gateNetName) < 0;
}

bool lessThanPosIndex(Transistor *t1, Transistor *t2)
{
    return t1->getPosIndex() < t2->getPosIndex();
}

void Cell::sortByGateNetName()
{
    qSort(nTransistors->begin(), nTransistors->end(), lessThanGateNetName);
    qSort(pTransistors->begin(), pTransistors->end(), lessThanGateNetName);
}


void Cell::sortByPosIndex()
{
    qSort(nTransistors->begin(), nTransistors->end(), lessThanPosIndex);
    qSort(pTransistors->begin(), pTransistors->end(), lessThanPosIndex);
}

void Cell::mergeTransistors(QList<Transistor *> *transistors)
{
    for(int i=0; i< transistors->size();)
    {
        Transistor *curT = transistors->at(i);

        while(++i<transistors->size())
        {
            Transistor *nextT = transistors->at(i);

            if(curT->gateNetName.compare(nextT->gateNetName) == 0     &&
               curT->sourceNetName.compare(nextT->sourceNetName) == 0 &&
               curT->drainNetName.compare(nextT->drainNetName) == 0)
            {
                curT->setW(curT->w + nextT->w);
                nextT->setGateNetName("-1");
            }
            else
                break;
        }
    }
    recursiveRemoveTransistor(transistors);
}
void Cell::recursiveRemoveTransistor(QList<Transistor *> *transistors)
{
    foreach(Transistor *t, *(transistors))
    {
        if(t->gateNetName.compare("-1") == 0)
        {
            transistors->removeOne(t);
            recursiveRemoveTransistor(transistors);
        }
    }
}

void Cell::mergeTransistors()
{
    mergeTransistors(nTransistors);
    mergeTransistors(pTransistors);
}

void Cell::folding(QList<Transistor *> *transistors)
{
    int lastIndex = 1;
    qreal h = pmosHeight;

    if(transistors->first()->transistorType.compare("NMOS") == 0)
        h = nmosHeight;

    foreach(Transistor *t, *(transistors))
    {
        int div = ceil( t->gateRect.height() / (h - (Rules::getRule("PP.E.1") - Rules::getRule("PO.O.1") + (Rules::getRule("CO.O.2")*2) + Rules::getRule("CO.W.1") + (Rules::getRule("PO.S.1")/2))));

        if( div > 1)
        {
            for(int i=0; i<div; i++)
            {
                Transistor* newT = new Transistor();
                newT->setPosIndex(lastIndex++);
                newT->setTransistorName(t->transistorName);
                newT->setSourceNetName(t->sourceNetName);
                newT->setGateNetName(t->gateNetName);
                newT->setDrainNetName(t->drainNetName);
                newT->setBulkNetName(t->bulkNetName);
                newT->setTransistorType(t->transistorType);
                newT->setL(t->l);
                newT->setW(t->w/div);
                newT->scale = t->scale;
                newT->flipped = false;

                if(i%2 != 0)
                    newT->flipped = true;

                transistors->push_front(newT);
            }
            t->setGateNetName("-1");
        }
        else
            t->setPosIndex(lastIndex++);
    }
}

void Cell::releaseMemory(QList<Metal*>* items)
{
    if(items)
    {
        foreach(Metal* m, *(items))
        {
            if(m)
            {
                delete m->linkedTransistors;
                delete m;
                m = 0;
            }
        }

        delete items;
        items = 0;
    }
}

void Cell::releaseMemory(QList<Transistor *> *transistors)
{
    if(transistors)
    {
        foreach(Transistor* t, *(transistors))
        {
            if(t)
            {
                delete t;
                t = 0;
            }
        }

        delete transistors;
        transistors = 0;
    }
}

void Cell::releaseMemory()
{
    releaseMemory(metalItems);
    releaseMemory(m1Items);
    releaseMemory(m2Items);
    releaseMemory(m1PinItems);
    releaseMemory(poItems);
    releaseMemory(diffItems);
    releaseMemory(coItems);
    releaseMemory(m1PinItems);

    releaseMemory(pTransistors);
    releaseMemory(nTransistors);

    delete gndRectItem;
    delete nWellRectItem;
    delete nPlusRectItem;
    delete pPlusRectItem;
    delete vccStrapItem;
    delete gndStrapItem;
}

void Cell::folding()
{
    mergeTransistors();
    folding(pTransistors);
    folding(nTransistors);
    recursiveRemoveTransistor(pTransistors);
    recursiveRemoveTransistor(nTransistors);
    sortByPosIndex();
}

QGraphicsScene* Cell::getM1Scene()
{
    QGraphicsScene* m1Scene = new QGraphicsScene();

    foreach(Metal* m, *(this->m1Items))
    {
        Metal *newM1 = new Metal();

        newM1->bottomRight = m->bottomRight;
        newM1->metalType = "M1";

        m1Scene->addItem(newM1);

        newM1->setPos(m->scenePos());
    }

    return m1Scene;
}

QStringList* Cell::getGateNets()
{
    QStringList* nets = new QStringList();

    foreach(Transistor *t, *pTransistors)
        nets->append(t->gateNetName);

    foreach(Transistor *t, *nTransistors)
        nets->append(t->gateNetName);

    nets->removeDuplicates();

    return nets;
}

QString Cell::removeOutSideRoutedM1()
{
    QStringList fail;

    foreach(Metal *m1, *(m1Items))
        if( (m1->y() < 0 || m1->y() > gndRectItem->y() || fail.contains(m1->net) ) && m1->net.compare("vcc") != 0)
            fail.append(m1->net);

    fail.removeDuplicates();

    if(!fail.empty())
    {
        foreach(Metal *m1, *(m1Items))
            if(fail.contains(m1->net))
                m1Items->removeOne(m1);

        foreach(Metal *co, *(coItems))
            if(fail.contains(co->net))
                coItems->removeOne(co);

        foreach(Metal *diff, *(diffItems))
            if(fail.contains(diff->net))
                diffItems->removeOne(diff);

        foreach(Metal *po, *(poItems))
            if(fail.contains(po->net))
                poItems->removeOne(po);
    }

    QString ret;
    foreach(QString net, fail)
        ret.append(net + " ");

    return ret;
}

void Cell::refreshScenePositions()
{
    this->setTransistorsScenePosition();
    this->setPPlusPosition();
    this->setNPlusPosition();
    this->setVccGndStraps();
    this->setVccGndPosition();
    this->setNWellPosition();
    this->setTransistorYPosition();
}

void Cell::addItemsToScene(QGraphicsScene* scene)
{
    scene->addLine(-100000,0,100000,0,QPen(Qt::white, 0));
    scene->addLine(0,-100000,0,100000,QPen(Qt::white, 0));

    foreach(Transistor* t, *pTransistors)
        scene->addItem(t);
    foreach(Transistor* t, *nTransistors)
        scene->addItem(t);

    foreach(Metal* m, *metalItems)
        scene->addItem(m);

    foreach(Metal* m, *m1Items)
        scene->addItem(m);

    foreach(Metal* m, *m2Items)
        scene->addItem(m);

    foreach(Metal* m, *m1PinItems)
        scene->addItem(m);

    foreach(Metal* m, *poItems)
        scene->addItem(m);

    foreach(Metal* m, *diffItems)
        scene->addItem(m);

    foreach(Metal* m, *coItems)
        scene->addItem(m);

    foreach(Via* v, *vias)
        scene->addItem(v);

    scene->addItem(vccStrapItem);
    scene->addItem(gndStrapItem);
}

void Cell::setShowLabel(bool showLabels)
{
    foreach(Transistor* t, *pTransistors)
        t->drawNetNames = showLabels;

    foreach(Transistor* t, *nTransistors)
        t->drawNetNames = showLabels;

    foreach(Metal* m, *metalItems)
        m->drawNetName = showLabels;

    foreach(Metal* m, *m1Items)
        m->drawNetName = showLabels;

    foreach(Metal* m, *m1PinItems)
        m->drawNetName = showLabels;

    foreach(Metal* m, *poItems)
        m->drawNetName = showLabels;

    foreach(Metal* m, *diffItems)
        m->drawNetName = showLabels;

    foreach(Metal* m, *coItems)
        m->drawNetName = showLabels;
}

QString Cell::toString()
{
    QString str = ".subckt";

    foreach(QString pin, this->pins)
        str.append( " " + pin);

    str.append("\n");

    foreach(Transistor *t, *(this->nTransistors))
        str.append(t->transistorName + " " +
                   t->sourceNetName + " " +
                   t->gateNetName + " " +
                   t->drainNetName + " " +
                   t->bulkNetName +
                   " NMOS L=" +
                   QString::number(t->l/100) + "U W=" +
                   QString::number(t->w/100) + "U\n");

    foreach(Transistor *t, *(this->pTransistors))
        str.append(t->transistorName + " " +
                   t->sourceNetName + " " +
                   t->gateNetName + " " +
                   t->drainNetName + " " +
                   t->bulkNetName +
                   " PMOS L=" +
                   QString::number(t->l/100) + "U W=" +
                   QString::number(t->w/100) + "U\n");

    str.append(".ends\n");

    return str;
}

qreal Cell::getPmosGateMinY(QString net)
{
    qreal minY = 0;

    foreach(Transistor *t, *(this->pTransistors))
        if(t->gateNetName == net && minY < t->getGatePos().y())
            minY = t->getGatePos().y();

    return minY;
}

void Cell::exportAsCif(QString fileName)
{
    QFile file(fileName);

    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);

    out << "DS 1 1 1;" << endl;
    out << "9 " + cellName + ";" << endl;

    out << "L 31;" << endl;
    foreach(Metal* m, *m1Items)
        out << "P " + m->getCoordinates() << endl;

    out << "L 31;" << endl;
    foreach(Metal* m, *m2Items)
        out << "P " + m->getCoordinates() << endl;

    out << "L 131;" << endl;
    foreach(Metal* m, *m1PinItems)
    {
        out << "P " + m->getCoordinates() << endl;
        QPointF center = m->pos() + m->boundingRect().center();
        out << "94 " + m->net + " " + QString::number(((int)center.x()*10)) + "," + QString::number(((int)(center.y()*10))) + ";" << endl;
    }

    out << "L 6;" << endl;
    foreach(Metal* m, *diffItems)
        out << "P " + m->getCoordinates() << endl;

    vccStrapItem->printDiffCifFormat(&out);
    gndStrapItem->printDiffCifFormat(&out);

    foreach(Transistor *t, *pTransistors)
        t->printDiffCifFormat(&out);

    foreach(Transistor *t, *nTransistors)
        t->printDiffCifFormat(&out);

    out << "L 17;" << endl;
    foreach(Metal* m, *poItems)
        out << "P " + m->getCoordinates() << endl;

    foreach(Transistor *t, *pTransistors)
        t->printPoCifFormat(&out);

    foreach(Transistor *t, *nTransistors)
        t->printPoCifFormat(&out);

    out << "L 30;" << endl;
    foreach(Metal* m, *coItems)
        out << "P " + m->getCoordinates() << endl;

    vccStrapItem->printCoCifFormat(&out);
    gndStrapItem->printCoCifFormat(&out);

    out << "L 3;" << endl;
    out << "P " + nWellRectItem->getCoordinates() << endl;

    out << "L 26;" << endl;
    out << "P " + nPlusRectItem->getCoordinates() << endl;
    vccStrapItem->printNpPpCifFormat(&out);

    out << "L 25;" << endl;
    out << "P " + pPlusRectItem->getCoordinates() << endl;
    gndStrapItem->printNpPpCifFormat(&out);

    out << "DF;"  << endl;
    out << "C 1;"  << endl;
    out << "E"  << endl;
}

qreal Cell::getNmosGateMaxY(QString net)
{
    qreal maxY = 9e5;

    foreach(Transistor *t, *(this->nTransistors))
        if(t->gateNetName == net && maxY > t->getGatePos().y())
            maxY = t->getGatePos().y();

    return maxY;
}

qreal Cell::getNmosGateMinY(QString net)
{
    qreal minY = 0;

    foreach(Transistor *nt, *(this->nTransistors))
    {
        if(nt->gateNetName == net)
        {
            foreach(Transistor *pt, *(this->pTransistors))
            {
                QPointF ngPos = nt->getGatePos();
                QPointF pgPos = pt->getGatePos();

                if(abs(ngPos.x() - pgPos.x()) < 14  && (minY < pgPos.y() + 14))
                    minY = pgPos.y() + 14;
            }
        }
    }

    return minY;
}

qreal Cell::getPmosGateMaxY(QString net)
{
    qreal maxY = 5e9;

    foreach(Transistor *pt, *(this->pTransistors))
    {
        if(pt->gateNetName == net)
        {
            foreach(Transistor *nt, *(this->nTransistors))
            {
                QPointF ngPos = nt->getGatePos();
                QPointF pgPos = pt->getGatePos();

                if(abs(ngPos.x() - pgPos.x()) < 14  && (maxY > pgPos.y() - 14))
                    maxY = pgPos.y() - 14;
            }
        }
    }
    return maxY;
}

void Cell::reset()
{
    foreach(Transistor *t, *(this->nTransistors))
        t->flipped = false;

    foreach(Transistor *t, *(this->pTransistors))
        t->flipped = false;
}

QString Cell::getCellSize()
{
    qreal x = vccRectItem->bottomRight.x() / factor;
    qreal y = (gndRectItem->y() + gndRectItem->bottomRight.y())/factor;

    return QString::number(x,'g', 3) + " x " + QString::number(y,'g', 3);
}
